grammar Go;
options {backtrack=true; memoize=true;}

@lexer::members {

}



fragment 
Unicode_char   
	: '\u0003'..'\uffff';

fragment 
Unicode_letter
    :  '\u0024' |
       '\u0041'..'\u005a' |
       '\u0061'..'\u007a' |
       '\u00c0'..'\u00d6' |
       '\u00d8'..'\u00f6' |
       '\u00f8'..'\u00ff' |
       '\u0100'..'\u1fff' |
       '\u3040'..'\u318f' |
       '\u3300'..'\u337f' |
       '\u3400'..'\u3d2d' |
       '\u4e00'..'\u9fff' |
       '\uf900'..'\ufaff'
    ;

fragment 
Unicode_digit  
    :  '\u0030'..'\u0039' |
       '\u0660'..'\u0669' |
       '\u06f0'..'\u06f9' |
       '\u0966'..'\u096f' |
       '\u09e6'..'\u09ef' |
       '\u0a66'..'\u0a6f' |
       '\u0ae6'..'\u0aef' |
       '\u0b66'..'\u0b6f' |
       '\u0be7'..'\u0bef' |
       '\u0c66'..'\u0c6f' |
       '\u0ce6'..'\u0cef' |
       '\u0d66'..'\u0d6f' |
       '\u0e50'..'\u0e59' |
       '\u0ed0'..'\u0ed9' |
       '\u1040'..'\u1049'
   ;

fragment
Letter        
	:	Unicode_letter | '_' ;

fragment
Decimal_digit 
	:	 '0'..'9' ;

fragment	
Octal_digit   
	:	 '0'..'7' ;

fragment	
Hex_digit     
	:	'0'..'9' | 
		'A'..'F' | 
		'a'..'f' 
	;
 
LINE_COMMENT
    : '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    ;

COMMENT
    :   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
    ;

Identifier 
	:	 Letter ( Letter | Unicode_digit )* ;

fragment
Int_lit     
	:	 Decimal_lit | Octal_lit | Hex_lit ;

fragment
Decimal_lit 
	:	 ( '1'..'9' ) ( Decimal_digit )* ;

fragment
Octal_lit   
	:	 '0' ( Octal_digit )* ;

fragment
Hex_lit     
	:	 '0' ( 'x' | 'X' ) Hex_digit ( Hex_digit )* ;

fragment
Float_lit 
	:	 
	Decimals '.' ( Decimals )? ( Exponent )? |
	Decimals Exponent |
	'.' Decimals ( Exponent )? ;

fragment
Decimals  
	:	 Decimal_digit ( Decimal_digit ) ;

fragment
Exponent  
	:	 ( 'e' | 'E' ) ( '+' | '-' )? Decimals ;

Imaginary_lit 
	:	 (Decimals | Float_lit) 'i' ;

Char_lit         
	:	 '\'' ( Unicode_value | Byte_value ) '\'' ;

fragment
Unicode_value    
	:	 Unicode_char | Little_u_value | Big_u_value | Escaped_char ;

fragment
Byte_value       
	:	 Octal_byte_value | Hex_byte_value ;

fragment
Octal_byte_value 
	:	 '\\' Octal_digit Octal_digit Octal_digit ;

fragment
Hex_byte_value   
	:	 '\\' 'x' Hex_digit Hex_digit ;

fragment
Little_u_value   
	:	 '\\' 'u' Hex_digit Hex_digit Hex_digit Hex_digit ;

fragment
Big_u_value      
	:	 '\\' 'U' Hex_digit Hex_digit Hex_digit Hex_digit
                            Hex_digit Hex_digit Hex_digit Hex_digit ;
fragment
Escaped_char     
	:	 '\\' ( 'a' | 'b' | 'f' | 'n' | 'r' | 't' | 'v' | '\\' | '\'' | '"' ) ;

String_lit             
	:	 Raw_string_lit | Interpreted_string_lit ;

fragment
Raw_string_lit         
	:	 '`' ( Unicode_char )* '`' ;

// FIXME: hacked due to ANTLR complaining: The following alternatives can never be matched: 2
fragment
Interpreted_string_lit 
	:	'"' ( Escaped_char | ~('\\'|'"') )* '"';

type      
	:	 typeName | typeLit | '(' type ')' ;
typeName  
	:	 qualifiedIdent;
typeLit   
	:	 arrayType | structType | pointerType | functionType | interfaceType |
	    sliceType | mapType | channelType ;

arrayType   
	:	 '[' arrayLength ']' elementType ;
arrayLength 
	:	 expression ;
elementType 
	:	 type ;

sliceType 
	:	 '[' ']' elementType ;

structType     
	:	 'struct' '{' ( fieldDecl ';' )* '}' ;
fieldDecl      
	:	 (identifierList type | anonymousField) (tag)? ;
anonymousField 
	:	 ('*')? typeName ;
tag            
	:	 String_lit ;

pointerType 
	:	 '*' baseType ;
baseType 
	:	 type ;

functionType   
	:	 'func' signature ;
signature      
	:	 parameters ( result )? ;
result         
	:	 parameters | type ;
parameters     
	:	 '(' ( parameterList ( ',' )? )? ')' ;
parameterList  
	:	 parameterDecl ( ',' parameterDecl )* ;
parameterDecl  
	:	 ( identifierList )? ( type | '...' ( type )? ) ;

interfaceType      
	:	 'interface' '{' ( methodSpec ';' )* '}' ;
methodSpec         
	:	 methodName signature | interfaceTypeName ;
methodName         
	:	 Identifier ;
interfaceTypeName  
	:	 typeName ;

mapType     
	:	 'map' '[' keyType ']' elementType ;
keyType     
	:	 type ;

channelType   
	:	 channel | sendChannel | recvChannel ;
channel       
	:	 'chan' elementType ;
sendChannel   
	:	 'chan' '<-' elementType ;
recvChannel   
	:	 '<-' 'chan' elementType ;

block 	:	 '{' ( statement ';' )* '}' ;

declaration   
	:	 constDecl | typeDecl | varDecl ;
topLevelDecl  
	:	 declaration | functionDecl | methodDecl ;

constDecl      
	:	 'const' ( constSpec | '(' ( constSpec ';' )* ')' ) ;
constSpec      
	:	 identifierList ( ( type )? '=' expressionList )? ;
 
identifierList 
	:	 Identifier ( ',' Identifier )* ;
expressionList 
	:	 expression ( ',' expression )* ;

typeDecl     
	:	 'type' ( typeSpec | '(' ( typeSpec ';' )* ')' ) ;
typeSpec     
	:	 Identifier type ;

varDecl     
	:	 'var' ( varSpec | '(' ( varSpec ';' )* ')' ) ;
varSpec     
	:	 identifierList ( type ( '=' expressionList )? | '=' expressionList ) ;

shortVarDecl 
	:	 identifierList ':=' expressionList ;

functionDecl 
	:	 'func' Identifier signature ( body )? ;
body         
	:	 block;

methodDecl   
	:	 'func' receiver methodName signature ( body )? ;
receiver     
	:	 '(' ( Identifier )? ( '*' )? baseTypeName ')' ;
baseTypeName 
	:	 Identifier ;

operand   
	:	 literal | qualifiedIdent | methodExpr | '(' expression ')' ;
literal    
	:	 basicLit | compositeLit | functionLit ;
basicLit   
	:	 Int_lit | Float_lit | Imaginary_lit | Char_lit | String_lit ;

qualifiedIdent 
	:	 ( packageName '.' )? Identifier ;

compositeLit  
	:	 literalType '{' ( elementList ( ',' )? )? '}' ;
literalType   
	:	 structType | arrayType | '[' '...' ']' elementType |
                sliceType | mapType | typeName | '(' literalType ')' ;
elementList   
	:	 element ( ',' element )* ;
element       
	:	 ( key ':' )? value ;
key           
	:	 fieldName | elementIndex ;
fieldName     
	:	 Identifier ;
elementIndex  
	:	 expression ;
value         
	:	 expression ;

functionLit 
	:	 functionType body ;

// Left recursion removed using ANTLRWorks
primaryExpr 
	:	
	(operand | conversion | builtinCall) (selector | index | slice | typeAssertion | call)* ;

selector       
	:	 '.' Identifier ;
index          
	:	 '[' expression ']' ;
slice          
	:	 '[' expression ':' ( expression )? ']' ;
typeAssertion  
	:	 '.' '(' type ')' ;
call           
	:	 '(' ( expressionList ( ',' )? )? ')' ;

// Left recursion removed using ANTLRWorks
expression 
	:	 (unaryExpr) (Binary_op unaryExpr)* ;
unaryExpr  
	:	 primaryExpr | Unary_op unaryExpr ;
 
Binary_op  
	:	 Log_op | Com_op | Rel_op | Add_op | Mul_op ;
fragment
Log_op     
	:	 '||' | '&&' ;
fragment
Com_op     
	:	 '<-' ;
fragment
Rel_op     
	:	 '==' | '!=' | '<' | '<=' | '>' | '>=' ;
fragment
Add_op     
	:	 '+' | '-' | '|' | '^' ;
fragment
Mul_op     
	:	 '*' | '/' | '%' | '<<' | '>>' | '&' | '&^' ;
fragment
Unary_op   
	:	 '+' | '-' | '!' | '^' | '*' | '&' | '<-' ;

methodExpr    
	:	 receiverType '.' methodName ;
receiverType  
	:	 typeName | '(' '*' typeName ')' ;

conversion 
	:	 literalType '(' expression ')' ;

statement 
	:	
	declaration | labeledStmt | simpleStmt |
	goStmt | returnStmt | breakStmt | continueStmt | gotoStmt |
	fallthroughStmt | block | ifStmt | switchStmt | selectStmt | forStmt |
	deferStmt ;

simpleStmt 
	:	 emptyStmt | expressionStmt | incDecStmt | assignment | shortVarDecl ;


emptyStmt 
	:	 ;

labeledStmt 
	:	 label ':' statement ;
label       
	:	 Identifier ;

expressionStmt 
	:	 expression ;

incDecStmt 
	:	 expression ( '++' | '--' ) ;

assignment 
	:	 expressionList Assign_op expressionList ;

Assign_op 
	:	 ( Add_op | Mul_op )? '=' ;

ifStmt    
	:	 'if' ( simpleStmt ';' )? ( expression )? block ( 'else' statement )? ;

switchStmt 
	:	 exprSwitchStmt | typeSwitchStmt ;

exprSwitchStmt 
	:	 'switch' ( simpleStmt ';' )? ( expression )? '{' ( exprCaseClause )* '}' ;
exprCaseClause 
	:	 exprSwitchCase ':' ( statement ';' )? ;
exprSwitchCase 
	:	 'case' expressionList | 'default' ;

typeSwitchStmt  
	:	 'switch' ( simpleStmt ';' )? typeSwitchGuard '{' ( typeCaseClause )* '}' ;
typeSwitchGuard 
	: ( Identifier ':=' )? primaryExpr '.' '(' 'type' ')' ;
typeCaseClause  
	: typeSwitchCase ':' ( statement ';' )* ;
typeSwitchCase  
	: 'case' typeList | 'default' ;
typeList        
	: type ( ',' type )* ;

forStmt 
	:	 'for' ( condition | forClause | rangeClause )? block ;
condition 
	:	 expression ;

forClause 
	:	 ( initStmt )? ';' ( condition )? ';' ( postStmt )? ;
initStmt 
	:	 simpleStmt ;
postStmt 
	:	 simpleStmt ;

rangeClause 
	:	 expressionList ( '=' | ':=' ) 'range' expression ;

goStmt 	
	:	 'go' expression ;

selectStmt 
	:	 'select' '{' ( commClause )* '}' ;
commClause 
	:	 commCase ':' ( statement ';' )? ;
commCase 
	:	 'case' ( sendExpr | recvExpr) | 'default' ;
sendExpr 
	:	 expression '<-' expression ;
recvExpr 
	:	 ( expression ( '=' | ':=' ) )? '<-' expression ;

returnStmt 
	: 'return' ( expressionList )? ;

breakStmt 
	:	 'break' ( label )? ;

continueStmt 
	:	 'continue' ( label )? ;


gotoStmt 
	: 'goto' label ;

fallthroughStmt 
	:	 'fallthrough' ;

deferStmt 
	:	 'defer' expression;

builtinCall 
	:	 Identifier '(' ( builtinArgs )? ')' ;
builtinArgs 
	:	 type ( ',' expressionList )? | expressionList ;

sourceFile       
	:	 packageClause ';' ( importDecl ';' )* ( topLevelDecl ';' )* ;

packageClause  
	:	 'package' packageName ;
packageName    
	:	 Identifier ;

importDecl       
	:	 'import' ( importSpec | '(' ( importSpec ';' )* ')' ) ;
importSpec       
	:	 ( '.' | packageName )* importPath ;
importPath       
	:	 String_lit ;
